/*
 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.spi.servicecontext;

import org.omg.CORBA.SystemException;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA_2_3.portable.InputStream;
import org.omg.CORBA_2_3.portable.OutputStream;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.impl.encoding.CDRInputStream;
import com.sun.corba.se.impl.encoding.EncapsInputStream;
import com.sun.corba.se.impl.encoding.EncapsOutputStream;
import com.sun.corba.se.impl.orbutil.ORBUtility;

/**
 * Base class for all ServiceContext classes.
 * There is a derived ServiceContext class for each service context that
 * the ORB supports.  Each subclass encapsulates the representation of
 * the service context and provides any needed methods for manipulating
 * the service context.  Each subclass must provide the following
 * members:
 * <p>
 * <ul>
 * </li>a public static final int SERVICE_CONTEXT_ID that gives the OMG
 * (or other) defined id for the service context.  This is needed for the
 * registration mechanism defined in ServiceContexts. OMG defined
 * service context ids are taken from section 13.6.7 of ptc/98-12-04.</li>
 * <li>a public constructor that takes an InputStream as its argument.</li>
 * <li>Appropriate definitions of getId() and writeData().  getId() must
 * return SERVICE_CONTEXT_ID.</li>
 * </ul>
 * <p>
 * The subclass can be constructed either directly from the service context
 * representation, or by reading the representation from an input stream.
 * These cases are needed when the service context is created and written to
 * the request or reply, and when the service context is read from the
 * received request or reply.
 */
public abstract class ServiceContext {

  /**
   * Simple default constructor used when subclass is constructed
   * from its representation.
   */
  protected ServiceContext() {
  }

  private void dprint(String msg) {
    ORBUtility.dprint(this, msg);
  }

  /**
   * Stream constructor used when subclass is constructed from an
   * InputStream.  This constructor must be called by super( stream )
   * in the subclass.  After this constructor completes, the service
   * context representation can be read from in.
   * Note that the service context id has been consumed from the input
   * stream before this object is constructed.
   */
  protected ServiceContext(InputStream s, GIOPVersion gv) throws SystemException {
    in = s;
  }

  /**
   * Returns Service context id.  Must be overloaded in subclass.
   */
  public abstract int getId();

  /**
   * Write the service context to an output stream.  This method
   * must be used for writing the service context to a request or reply
   * header.
   */
  public void write(OutputStream s, GIOPVersion gv) throws SystemException {
    EncapsOutputStream os =
        sun.corba.OutputStreamFactory.newEncapsOutputStream((ORB) (s.orb()), gv);
    os.putEndian();
    writeData(os);
    byte[] data = os.toByteArray();

    s.write_long(getId());
    s.write_long(data.length);
    s.write_octet_array(data, 0, data.length);
  }

  /**
   * Writes the data used to represent the subclasses service context
   * into an encapsulation stream.  Must be overloaded in subclass.
   */
  protected abstract void writeData(OutputStream os);

  /**
   * in is the stream containing the service context representation.
   * It is constructed by the stream constructor, and available for use
   * in the subclass stream constructor.
   */
  protected InputStream in = null;

  public String toString() {
    return "ServiceContext[ id=" + getId() + " ]";
  }
}
